nmCryptokit.chromeExtension = 'dhpndmcckjjkkbaaolhnkggnphdeacln';
nmCryptokit.edgeExtension = 'edeefnpodfhpcepgkiokdhdlgfblbkfl';
nmCryptokit.productID = 'com.cfca.cryptokit.gtja';

nmCryptokit.extensionName = nmCryptokit.productID + '.extension';
nmCryptokit.reqEventName = nmCryptokit.productID + '.request';
nmCryptokit.respEventName = nmCryptokit.productID + '.response';

nmCryptokit.Browser = {
  IE: 'Internet Explorer',
  Edge: 'Edge',
  Edg: 'Edge(Chromium)',
  Chrome: 'Chrome',
  Safari: 'Safari',
  Firefox: 'Firefox'
};

function GenerateRandomId () {
  var charstring = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890';
  var maxPos = charstring.length;
  var randomId = '';
  for (var i = 0; i < 10; i++) {
    randomId += charstring.charAt(Math.floor(Math.random() * maxPos));
  }
  return randomId;
}

export function nmCryptokit (browser) {
  this.browser = browser;
};

// Encapsulate Chrome sendMessage callback to Promise
nmCryptokit.SendMessageforChrome = function (request) {
  console.info('SendMessageforChrome');
  return new Promise(function (resolve, reject) {
    chrome.runtime.sendMessage(nmCryptokit.chromeExtension, request, function (response) {
      if (response) {
        if (response.errorcode == 0) {
          resolve(response);
        } else {
          reject(response);
        }
      } else {
        var result = new Object();
        result.errorcode = 1;
        result.result = chrome.runtime.lastError.message;
        reject(result);
      }
    });
  });
};

// Encapsulate Chrome sendMessage callback to Promise
nmCryptokit.SendMessageforEdge = function (request) {
  console.info('SendMessageforEdge');
  return new Promise(function (resolve, reject) {
    chrome.runtime.sendMessage(nmCryptokit.edgeExtension, request, function (response) {
      if (response) {
        if (response.errorcode == 0) {
          resolve(response);
        } else {
          reject(response);
        }
      } else {
        var result = new Object();
        result.errorcode = 1;
        result.result = chrome.runtime.lastError.message;
        reject(result);
      }
    });
  });
};

// Encapsulate Edge&Firefox event to Promise
nmCryptokit.SendMessagebyEvent = function (request) {
  var event = new CustomEvent(nmCryptokit.reqEventName, { detail: request });
  document.dispatchEvent(event);

  return new Promise(function (resolve, reject) {
    var responseEventName = nmCryptokit.respEventName;
    if (request.funcInfo != undefined && request.funcInfo.randomId != undefined) { responseEventName += ('.' + request.funcInfo.randomId); }

    document.addEventListener(responseEventName, function CallBack (e) {
      document.removeEventListener(e.type, CallBack);
      var eJson = JSON.parse(e.detail);
      if (eJson != null && eJson.errorcode == 0) {
        resolve(eJson);
      } else {
        reject(eJson);
      }
    }, false);
  });
};

nmCryptokit.SendMessage = function (browser, requestJSON) {
  if (nmCryptokit.Browser.Chrome == browser) {
    return nmCryptokit.SendMessageforChrome(requestJSON);
  } else if (nmCryptokit.Browser.Edg == browser) {
    return nmCryptokit.SendMessageforEdge(requestJSON);
  } else {
    return nmCryptokit.SendMessagebyEvent(requestJSON);
  }
};

nmCryptokit.checkExtension = function (browser) {
  return new Promise(function (resolve, reject) {
    var result = new Object();
    if (nmCryptokit.Browser.Chrome == browser || nmCryptokit.Browser.Edg == browser) {
      // chrome.runtime.sendMessage() could check extension  existence.
      if (chrome.runtime) {
        resolve(browser);
      } else {
        result.errorcode = 2;
        result.result = 'Extension does not exist!';
        reject(result);
      }
    } else if (nmCryptokit.Browser.Edge == browser || nmCryptokit.Browser.Firefox == browser) {
      if (document.getElementById(nmCryptokit.extensionName)) {
        resolve(browser);
      } else {
        result.errorcode = 2;
        result.result = 'Extension does not exist!';
        reject(result);
      }
    } else {
      result.errorcode = 3;
      result.result = 'Only support Chrome/Edge/Firefox';
      reject(result);
    }
  });
};

nmCryptokit.prototype.init = function () {
  var browser = this.browser;

  return nmCryptokit.checkExtension(browser)
      .then(function (browser) {
        var request = new Object();
        request.action = 'connect';
        request.host = nmCryptokit.productID;
        return nmCryptokit.SendMessage(browser, request);
      }).then(function () {
        var request = new Object();
        var funcInfo = new Object();
        var randomId = GenerateRandomId();
        funcInfo.function = 'checkHost';
        funcInfo.params = null;
        funcInfo.randomId = randomId;
        request.action = 'invoke';
        request.funcInfo = funcInfo;
        return nmCryptokit.SendMessage(browser, request);
      });
};

nmCryptokit.prototype.uninit = function () {
  var request = new Object();
  request.action = 'disconnect';
  request.host = nmCryptokit.productID;

  return nmCryptokit.SendMessage(this.browser, request);
};

nmCryptokit.prototype.getExtensionVersion = function () {
  var request = new Object();
  var funcInfo = new Object();
  var randomId = GenerateRandomId();

  funcInfo.function = 'getExtensionVersion';
  funcInfo.params = null;
  funcInfo.randomId = randomId;
  request.action = 'getExtensionVersion';
  request.funcInfo = funcInfo;

  return nmCryptokit.SendMessage(this.browser, request);
};

nmCryptokit.prototype.getHostVersion = function () {
  var request = new Object();
  var funcInfo = new Object();
  var randomId = GenerateRandomId();

  funcInfo.function = 'GetVersion';
  funcInfo.params = null;
  funcInfo.randomId = randomId;

  request.action = 'invoke';
  request.funcInfo = funcInfo;

  return nmCryptokit.SendMessage(this.browser, request);
};

nmCryptokit.prototype.setPublicKey = function (bstrPublicKey) {
  var request = new Object();
  var funcInfo = new Object();
  var paramArr = new Array();
  var randomId = GenerateRandomId();

  paramArr.push(bstrPublicKey);

  funcInfo.function = 'SetPublicKey';
  funcInfo.params = paramArr;
  funcInfo.randomId = randomId;

  request.action = 'invoke';
  request.funcInfo = funcInfo;

  return nmCryptokit.SendMessage(this.browser, request);
};

nmCryptokit.prototype.getHardInfo = function () {
  var request = new Object();
  var funcInfo = new Object();
  var randomId = GenerateRandomId();

  funcInfo.function = 'GetHardInfo';
  funcInfo.params = null;
  funcInfo.randomId = randomId;

  request.action = 'invoke';
  request.funcInfo = funcInfo;

  return nmCryptokit.SendMessage(this.browser, request);
};

nmCryptokit.prototype.getRandomNo = function (nLength) {
  var request = new Object();
  var funcInfo = new Object();
  var paramArr = new Array();
  var randomId = GenerateRandomId();

  paramArr.push(nLength);

  funcInfo.function = 'GetRandomNo';
  funcInfo.params = paramArr;
  funcInfo.randomId = randomId;

  request.action = 'invoke';
  request.funcInfo = funcInfo;

  return nmCryptokit.SendMessage(this.browser, request);
};

nmCryptokit.prototype.encryptWithPublicKey = function (bstrSource, bstrPublicKey) {
  var request = new Object();
  var funcInfo = new Object();
  var paramArr = new Array();
  var randomId = GenerateRandomId();

  paramArr.push(bstrSource);
  paramArr.push(bstrPublicKey);

  funcInfo.function = 'EncryptWithPublicKey';
  funcInfo.params = paramArr;
  funcInfo.randomId = randomId;

  request.action = 'invoke';
  request.funcInfo = funcInfo;

  return nmCryptokit.SendMessage(this.browser, request);
};

nmCryptokit.prototype.getMAC = function () {
  var request = new Object();
  var funcInfo = new Object();
  var randomId = GenerateRandomId();

  funcInfo.function = 'GetMAC';
  funcInfo.params = null;
  funcInfo.randomId = randomId;

  request.action = 'invoke';
  request.funcInfo = funcInfo;

  return nmCryptokit.SendMessage(this.browser, request);
};

nmCryptokit.prototype.getIP = function () {
  var request = new Object();
  var funcInfo = new Object();
  var randomId = GenerateRandomId();

  funcInfo.function = 'GetIP';
  funcInfo.params = null;
  funcInfo.randomId = randomId;

  request.action = 'invoke';
  request.funcInfo = funcInfo;

  return nmCryptokit.SendMessage(this.browser, request);
};

nmCryptokit.prototype.getDeviceInfo = function () {
  var request = new Object();
  var funcInfo = new Object();
  var randomId = GenerateRandomId();

  funcInfo.function = 'GetDeviceInfo';
  funcInfo.params = null;
  funcInfo.randomId = randomId;

  request.action = 'invoke';
  request.funcInfo = funcInfo;

  return nmCryptokit.SendMessage(this.browser, request);
};

nmCryptokit.prototype.encryptWithRandomNo = function (bstrSource, bstrRandomNo, bstrSecrecyCode2) {
  var request = new Object();
  var funcInfo = new Object();
  var paramArr = new Array();
  var randomId = GenerateRandomId();

  paramArr.push(bstrSource);
  paramArr.push(bstrRandomNo);
  paramArr.push(bstrSecrecyCode2);

  funcInfo.function = 'EncryptWithRandomNo';
  funcInfo.params = paramArr;
  funcInfo.randomId = randomId;

  request.action = 'invoke';
  request.funcInfo = funcInfo;

  return nmCryptokit.SendMessage(this.browser, request);
};

nmCryptokit.prototype.saveToken = function (bstrToken, bstrUserCode) {
  var request = new Object();
  var funcInfo = new Object();
  var paramArr = new Array();
  var randomId = GenerateRandomId();

  paramArr.push(bstrToken);
  paramArr.push(bstrUserCode);

  funcInfo.function = 'SaveToken';
  funcInfo.params = paramArr;
  funcInfo.randomId = randomId;

  request.action = 'invoke';
  request.funcInfo = funcInfo;

  return nmCryptokit.SendMessage(this.browser, request);
};

nmCryptokit.prototype.obtainToken = function (bstrUserCode) {
  var request = new Object();
  var funcInfo = new Object();
  var paramArr = new Array();
  var randomId = GenerateRandomId();

  paramArr.push(bstrUserCode);

  funcInfo.function = 'ObtainToken';
  funcInfo.params = paramArr;
  funcInfo.randomId = randomId;

  request.action = 'invoke';
  request.funcInfo = funcInfo;

  return nmCryptokit.SendMessage(this.browser, request);
};

nmCryptokit.prototype.selectCertificate = function (strSubjectDNFilter, strIssuerDNFilter, strSerialNo, strCSPNameList) {
  var request = new Object();
  var funcInfo = new Object();
  var paramArr = new Array();
  var randomId = GenerateRandomId();

  paramArr.push(strSubjectDNFilter);
  paramArr.push(strIssuerDNFilter);
  paramArr.push(strSerialNo);
  paramArr.push(strCSPNameList);

  funcInfo.function = 'SelectCertificate';
  funcInfo.params = paramArr;
  funcInfo.randomId = randomId;

  request.action = 'invoke';
  request.funcInfo = funcInfo;

  return nmCryptokit.SendMessage(this.browser, request);
};

nmCryptokit.prototype.getSignCertInfo = function (strInfoType) {
  var request = new Object();
  var funcInfo = new Object();
  var paramArr = new Array();
  var randomId = GenerateRandomId();

  paramArr.push(strInfoType);

  funcInfo.function = 'GetSignCertInfo';
  funcInfo.params = paramArr;
  funcInfo.randomId = randomId;

  request.action = 'invoke';
  request.funcInfo = funcInfo;

  return nmCryptokit.SendMessage(this.browser, request);
};

nmCryptokit.prototype.signMsgPKCS7 = function (strSource, strSelectedAlg, bAttached) {
  var request = new Object();
  var funcInfo = new Object();
  var paramArr = new Array();
  var randomId = GenerateRandomId();

  paramArr.push(strSource);
  paramArr.push(strSelectedAlg);
  paramArr.push(bAttached);

  funcInfo.function = 'SignMsgPKCS7';
  funcInfo.params = paramArr;
  funcInfo.randomId = randomId;

  request.action = 'invoke';
  request.funcInfo = funcInfo;

  return nmCryptokit.SendMessage(this.browser, request);
};

nmCryptokit.prototype.signFilePKCS7Detached = function (strFile, strSelectedAlg) {
  var request = new Object();
  var funcInfo = new Object();
  var paramArr = new Array();
  var randomId = GenerateRandomId();

  paramArr.push(strFile);
  paramArr.push(strSelectedAlg);

  funcInfo.function = 'SignFilePKCS7Detached';
  funcInfo.params = paramArr;
  funcInfo.randomId = randomId;

  request.action = 'invoke';
  request.funcInfo = funcInfo;

  return nmCryptokit.SendMessage(this.browser, request);
};

nmCryptokit.prototype.signMsgPKCS1 = function (strSource, strSelectedAlg) {
  var request = new Object();
  var funcInfo = new Object();
  var paramArr = new Array();
  var randomId = GenerateRandomId();

  paramArr.push(strSource);
  paramArr.push(strSelectedAlg);

  funcInfo.function = 'SignMsgPKCS1';
  funcInfo.params = paramArr;
  funcInfo.randomId = randomId;

  request.action = 'invoke';
  request.funcInfo = funcInfo;

  return nmCryptokit.SendMessage(this.browser, request);
};

nmCryptokit.prototype.CFCA_GetCSPInfo = function () {
  var request = new Object();
  var funcInfo = new Object();
  var paramArr = new Array();
  var randomId = GenerateRandomId();

  funcInfo.function = 'CFCA_GetCSPInfo';
  funcInfo.params = paramArr;
  funcInfo.randomId = randomId;

  request.action = 'invoke';
  request.funcInfo = funcInfo;

  return nmCryptokit.SendMessage(this.browser, request);
};

nmCryptokit.prototype.CFCA_SetCSPInfo = function (lKeyLength, bstrCSPName) {
  var request = new Object();
  var funcInfo = new Object();
  var paramArr = new Array();
  var randomId = GenerateRandomId();

  paramArr.push(lKeyLength);
  paramArr.push(bstrCSPName);

  funcInfo.function = 'CFCA_SetCSPInfo';
  funcInfo.params = paramArr;
  funcInfo.randomId = randomId;

  request.action = 'invoke';
  request.funcInfo = funcInfo;

  return nmCryptokit.SendMessage(this.browser, request);
};

nmCryptokit.prototype.CFCA_SetKeyAlgorithm = function (bstrKeyAlgorithm) {
  var request = new Object();
  var funcInfo = new Object();
  var paramArr = new Array();
  var randomId = GenerateRandomId();

  paramArr.push(bstrKeyAlgorithm);

  funcInfo.function = 'CFCA_SetKeyAlgorithm';
  funcInfo.params = paramArr;
  funcInfo.randomId = randomId;

  request.action = 'invoke';
  request.funcInfo = funcInfo;

  return nmCryptokit.SendMessage(this.browser, request);
};

nmCryptokit.prototype.CFCA_ImportEncryptCert = function (bstrEncryptedPrivateKey, bstrP7Cert, bstrContainerName, lEncryptCertPrivateKeyFlags) {
  var request = new Object();
  var funcInfo = new Object();
  var paramArr = new Array();
  var randomId = GenerateRandomId();

  paramArr.push(bstrEncryptedPrivateKey);
  paramArr.push(bstrP7Cert);
  paramArr.push(bstrContainerName);
  paramArr.push(lEncryptCertPrivateKeyFlags);

  funcInfo.function = 'CFCA_ImportEncryptCert';
  funcInfo.params = paramArr;
  funcInfo.randomId = randomId;

  request.action = 'invoke';
  request.funcInfo = funcInfo;

  return nmCryptokit.SendMessage(this.browser, request);
};

nmCryptokit.prototype.CFCA_GetContainer = function () {
  var request = new Object();
  var funcInfo = new Object();
  var paramArr = new Array();
  var randomId = GenerateRandomId();

  funcInfo.function = 'CFCA_GetContainer';
  funcInfo.params = paramArr;
  funcInfo.randomId = randomId;

  request.action = 'invoke';
  request.funcInfo = funcInfo;

  return nmCryptokit.SendMessage(this.browser, request);
};

nmCryptokit.prototype.CFCA_ImportSignCert = function (lCertType, bstrSignCert, bstrContainerName) {
  var request = new Object();
  var funcInfo = new Object();
  var paramArr = new Array();
  var randomId = GenerateRandomId();

  paramArr.push(lCertType);
  paramArr.push(bstrSignCert);
  paramArr.push(bstrContainerName);

  funcInfo.function = 'CFCA_ImportSignCert';
  funcInfo.params = paramArr;
  funcInfo.randomId = randomId;

  request.action = 'invoke';
  request.funcInfo = funcInfo;

  return nmCryptokit.SendMessage(this.browser, request);
};

nmCryptokit.prototype.CFCA_PKCS10CertRequisition = function (bstrSubjectDN, lCertType, lSignPrivateKeyGenerateFlags) {
  var request = new Object();
  var funcInfo = new Object();
  var paramArr = new Array();
  var randomId = GenerateRandomId();

  paramArr.push(bstrSubjectDN);
  paramArr.push(lCertType);
  paramArr.push(lSignPrivateKeyGenerateFlags);

  funcInfo.function = 'CFCA_PKCS10CertRequisition';
  funcInfo.params = paramArr;
  funcInfo.randomId = randomId;

  request.action = 'invoke';
  request.funcInfo = funcInfo;

  return nmCryptokit.SendMessage(this.browser, request);
};

nmCryptokit.prototype.CFCA_GetAllCertInfo = function (bstrCSPNameList) {
  var request = new Object();
  var funcInfo = new Object();
  var paramArr = new Array();
  var randomId = GenerateRandomId();

  paramArr.push(bstrCSPNameList);

  funcInfo.function = 'CFCA_GetAllCertInfo';
  funcInfo.params = paramArr;
  funcInfo.randomId = randomId;

  request.action = 'invoke';
  request.funcInfo = funcInfo;

  return nmCryptokit.SendMessage(this.browser, request);
};

nmCryptokit.prototype.getLastErrorDesc = function () {
  var request = new Object();
  var funcInfo = new Object();
  var randomId = GenerateRandomId();

  funcInfo.function = 'GetLastErrorDesc';
  funcInfo.params = null;
  funcInfo.randomId = randomId;

  request.action = 'invoke';
  request.funcInfo = funcInfo;

  return nmCryptokit.SendMessage(this.browser, request);
};
